﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using Utils;

namespace StockModel
{
	public class RawStockDataSource
	{
		#region Attributes

		private readonly IDataBaseClient _dbClient;
		private readonly ExchangeMarketDataSource _exchangeMarketDataSource;

		#endregion

		#region Constants

		private const string StockNamesQuery = "SELECT Name FROM Stocks WITH(NOLOCK) GROUP BY Name";
		private const string StocksFromNameQuery = "SELECT * FROM Stocks WITH(NOLOCK) WHERE Name LIKE '{0}'";
		private const string MarketFromStockAndDateQuery = "SELECT Name FROM ExchangeMarkets WITH(NOLOCK) WHERE Id IN(SELECT MarketId FROM StockGroups WHERE Id IN ( SELECT IdStockGroup FROM [StockGroups-Stocks] WHERE IdStock IN (SELECT Id FROM Stocks WHERE Symbol LIKE '{0}') AND ((CONVERT(smalldatetime, '{1}', 103) BETWEEN DATEADD(DAY,DATEDIFF(DAY,0,DateAdded),0) AND DATEADD(DAY,DATEDIFF(DAY,0,DateRemoved),0)) OR (CONVERT(smalldatetime, '{1}', 103) >= DATEADD(DAY,DATEDIFF(DAY,0,DateAdded),0) AND DateRemoved IS NULL))))";

		#endregion
		
		#region Public Methods

		public RawStockDataSource(IDataBaseClient dbClient, ExchangeMarketDataSource exchangeMarketDataSource)
		{
			_dbClient = dbClient;
			_exchangeMarketDataSource = exchangeMarketDataSource;
		}
		
		public IEnumerable<string> GetStockNames()
		{
			List<string> result = new List<string>();

			DataTable data = _dbClient.ExecuteQuery(StockNamesQuery);
			foreach (DataRow row in data.Rows)
			{
				result.Add(row[0].ToString());
			}

			return result;
		}

		public IEnumerable<Stock> GetStocks(string stockName)
		{
			List<Stock> result = new List<Stock>();

			DataTable data = _dbClient.ExecuteQuery(string.Format(StocksFromNameQuery, stockName));
			foreach (DataRow row in data.Rows)
			{
				Stock stock = new Stock(row["Symbol"].ToString(), row["Name"].ToString());
				result.Add(stock);
			}

			return result;
		}

		public ExchangeMarket GetMarket(Stock stock, DateTime date)
		{
			object market = _dbClient.ExecuteScalar(string.Format(MarketFromStockAndDateQuery, stock.Id.Code, date.Date));
			if (market == null)
			{
				throw new InvalidDataException("Cannot find the market for the stock " + stock.Id.Code + " and date " + date.ToString(CultureInfo.CurrentUICulture));
			}
			string dbMarketName = market.ToString();
			ExchangeMarketName marketName = (ExchangeMarketName)Enum.Parse(typeof(ExchangeMarketName), dbMarketName);
			return _exchangeMarketDataSource.Load(marketName);
		}

		public IEnumerable<DateTime> GetAvailableDays(string stockName)
		{
			// ReSharper disable PossibleMultipleEnumeration

			IEnumerable<DateTime> result = new List<DateTime>();
			QuotationDataSource quotationDataSource = new QuotationDataSource(_dbClient);

			IEnumerable<Stock> stocks = this.GetStocks(stockName);

			try
			{
				foreach (Stock stock in stocks)
				{
					result = result.Union(quotationDataSource.GetAvailableDays(stock));
				}
			}
			finally
			{
				foreach (Stock stock in stocks)
				{
					stock.Dispose();
				}
			}

			// ReSharper restore PossibleMultipleEnumeration

			return result;
		}

		#endregion
	}
}
